{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Resnet\n",
    "\n",
    "使用PyTorch实现Resnet，并训练CIFAR-10数据集"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "1.导入包"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "import matplotlib.pyplot as plt\n",
    "import torch\n",
    "import torch.nn as nn\n",
    "import torch.nn.functional as F\n",
    "import torch.optim as optim\n",
    "import torchvision\n",
    "from torchvision import transforms"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "2.实现pre-activation non-bottleneck residual 模块,其父类为 `torch.nn.Module`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [],
   "source": [
    "class PreActivationBlock(nn.Module):\n",
    "    \"\"\"Pre-activation residual block.\"\"\"\n",
    "\n",
    "    expansion = 1\n",
    "\n",
    "    def __init__(self, in_slices, slices, stride=1):\n",
    "        super(PreActivationBlock, self).__init__()\n",
    "\n",
    "        self.bn_1 = nn.BatchNorm2d(in_slices)\n",
    "        self.conv_1 = nn.Conv2d(in_channels=in_slices, out_channels=slices,\n",
    "                                kernel_size=3, stride=stride, padding=1,\n",
    "                                bias=False)\n",
    "\n",
    "        self.bn_2 = nn.BatchNorm2d(slices)\n",
    "        self.conv_2 = nn.Conv2d(in_channels=slices, out_channels=slices,\n",
    "                                kernel_size=3, stride=1, padding=1,\n",
    "                                bias=False)\n",
    "\n",
    "        # if the input/output dimensions differ use convolution for the shortcut\n",
    "        if stride != 1 or in_slices != self.expansion * slices:\n",
    "            self.shortcut = nn.Sequential(\n",
    "                nn.Conv2d(in_channels=in_slices,\n",
    "                          out_channels=self.expansion * slices,\n",
    "                          kernel_size=1,\n",
    "                          stride=stride,\n",
    "                          bias=False)\n",
    "            )\n",
    "\n",
    "    def forward(self, x):\n",
    "        out = F.relu(self.bn_1(x))\n",
    "\n",
    "        #  reuse bn+relu in down-sampling layers\n",
    "        shortcut = self.shortcut(out) if hasattr(self, 'shortcut') else x\n",
    "\n",
    "        out = self.conv_1(out)\n",
    "\n",
    "        out = F.relu(self.bn_2(out))\n",
    "        out = self.conv_2(out)\n",
    "\n",
    "        out += shortcut\n",
    "\n",
    "        return out"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "3.实现pre-activation bottleneck residual 模块"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [],
   "source": [
    "class PreActivationBottleneckBlock(nn.Module):\n",
    "    \n",
    "    expansion=4\n",
    "    def __init__(self,in_slices,slices,stride=1):\n",
    "        super(PreActivationBottleneckBlock,self).__init__()\n",
    "        self.bn_1=nn.BatchNorm2d(in_slices)\n",
    "        self.conv_1=nn.Conv2d(in_channels=in_slices,out_channels=slices,\n",
    "                              kernel_size=1,\n",
    "                              bias=False)\n",
    "        \n",
    "        self.bn_2=nn.BatchNorm2d(slices)\n",
    "        self.conv_2=nn.Conv2d(in_channels=slices,out_channels=slices,\n",
    "                              kernel_size=3,stride=stride,padding=1,\n",
    "                              bias=False)\n",
    "        \n",
    "        self.bn_3=nn.BatchNorm2d(slices)\n",
    "        self.conv_3=nn.Conv2d(in_channels=slices,out_channels=self.expansion*slices,\n",
    "                              kernel_size=1,\n",
    "                              bias=False)\n",
    "        \n",
    "        if stride!=1 or in_slices!=self.expansion*slices:\n",
    "            self.shortcut=nn.Sequential(\n",
    "                nn.Conv2d(in_channels=in_slices,\n",
    "                          out_channels=self.expansion*slices,\n",
    "                          kernel_size=1,stride=stride,\n",
    "                          bias=False)\n",
    "            )\n",
    "            \n",
    "    def forward(self,x):\n",
    "        out=F.relu(self.bn_1(x))\n",
    "        \n",
    "        shortcut=self.shortcut(out) if hasattr(self,'shortcut') else x\n",
    "        out=self.conv_1(out)\n",
    "        out=F.relu(self.bn_2(out))\n",
    "        out=self.conv_2(out)\n",
    "        out=F.relu(self.bn_3(out))\n",
    "        out=self.conv_3(out)\n",
    "        out+=shortcut\n",
    "        \n",
    "        return out\n",
    "        "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "4.实现可配置的ResNet class,该类可以由上面的两种 pre-activation blocks构成。该网络包括了： input the type of pre-activation block, the number of residual groups, the number of residual blocks in each group, and the number of output classes (CIFAR-10中为10分类). 该类通过不同形参构造"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [],
   "source": [
    "class PreActivationResNet(nn.Module):\n",
    "    \n",
    "    def __init__(self,block,num_blocks,num_classes=10):\n",
    "        super(PreActivationResNet,self).__init__()\n",
    "        \n",
    "        self.in_slices=64\n",
    "        \n",
    "        self.conv_1=nn.Conv2d(in_channels=3,out_channels=64,\n",
    "                              kernel_size=3,stride=1,padding=1,\n",
    "                              bias=False)\n",
    "        \n",
    "        self.layer_1=self._make_group(block,64,num_blocks[0],stride=1)\n",
    "        self.layer_2=self._make_group(block,128,num_blocks[1],stride=2)\n",
    "        self.layer_3=self._make_group(block,256,num_blocks[2],stride=2)\n",
    "        self.layer_4=self._make_group(block,512,num_blocks[3],stride=2)\n",
    "        self.linear=nn.Linear(512*block.expansion,num_classes)\n",
    "\n",
    "\n",
    "    def _make_group(self,block,slices,num_blocks,stride):\n",
    "\n",
    "        strides=[stride]+[1]*(num_blocks-1)\n",
    "        layers=[]\n",
    "        for stride in strides:\n",
    "            layers.append(block(self.in_slices,slices,stride))\n",
    "            self.in_slices=slices*block.expansion\n",
    "\n",
    "        return nn.Sequential(*layers)\n",
    "    \n",
    "\n",
    "    def forward(self,x):\n",
    "        out=self.conv_1(x)\n",
    "        out=self.layer_1(out)\n",
    "        out=self.layer_2(out)\n",
    "        out=self.layer_3(out)\n",
    "        out=self.layer_4(out)\n",
    "        out=F.avg_pool2d(out,4)\n",
    "        out=out.view(out.size(0),-1)\n",
    "        out=self.linear(out)\n",
    "\n",
    "        return out"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "5.根据论文构造几个`PreActivationResNet` configurations"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [],
   "source": [
    "def PreActivationResNet18():\n",
    "    return PreActivationResNet(block=PreActivationBlock,\n",
    "                               num_blocks=[2,2,2,2])\n",
    "\n",
    "def PreActivationResNet34():\n",
    "    return PreActivationResNet(block=PreActivationBlock,\n",
    "                               num_blocks=[3,4,6,3])\n",
    "\n",
    "def PreActivationResNet50():\n",
    "    return PreActivationResNet(block=PreActivationBottleneckBlock,\n",
    "                               num_blocks=[3,4,6,3])\n",
    "\n",
    "def PreActivationResNet101():\n",
    "    return PreActivationResNet(block=PreActivationBottleneckBlock,\n",
    "                               num_blocks=[3,4,23,3])\n",
    "\n",
    "def PreActivationResNet152():\n",
    "    return PreActivationResNet(block=PreActivationBottleneckBlock,\n",
    "                               num_blocks=[3,8,36,3])\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "6.构造常规的训练model"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [],
   "source": [
    "def train_model(model,loss_function,optimizer,data_loader):\n",
    "    model.train()\n",
    "    current_loss=0.0\n",
    "    current_acc=0\n",
    "\n",
    "    for i,(inputs,labels) in enumerate(data_loader):\n",
    "        inputs=inputs.to(device)\n",
    "        labels=labels.to(device)\n",
    "\n",
    "        optimizer.zero_grad()\n",
    "\n",
    "        with torch.set_grad_enabled(True):\n",
    "            outputs=model(inputs)\n",
    "            _,predictions=torch.max(outputs,1)\n",
    "            loss=loss_function(outputs,labels)\n",
    "\n",
    "            loss.backward()\n",
    "            optimizer.step()\n",
    "\n",
    "        current_loss+=loss.item()*inputs.size(0)\n",
    "        current_acc+=torch.sum(predictions==labels.data)\n",
    "    \n",
    "    total_loss=current_loss/len(data_loader.dataset)\n",
    "    total_acc=current_acc.double()/len(data_loader.dataset)\n",
    "\n",
    "    print('Train Loss:{:.4f}; Accuracy:{:.4f}'.format(total_loss,total_acc))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "7.验证模型"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [],
   "source": [
    "def test_model(model, loss_function, data_loader):\n",
    "    \"\"\"Test for a single epoch\"\"\"\n",
    "\n",
    "    # set model in evaluation mode\n",
    "    model.eval()\n",
    "\n",
    "    current_loss = 0.0\n",
    "    current_acc = 0\n",
    "\n",
    "    # iterate over  the validation data\n",
    "    for i, (inputs, labels) in enumerate(data_loader):\n",
    "        # send the input/labels to the GPU\n",
    "        inputs = inputs.to(device)\n",
    "        labels = labels.to(device)\n",
    "\n",
    "        # forward\n",
    "        with torch.set_grad_enabled(False):\n",
    "            outputs = model(inputs)\n",
    "            _, predictions = torch.max(outputs, 1)\n",
    "            loss = loss_function(outputs, labels)\n",
    "\n",
    "        # statistics\n",
    "        current_loss += loss.item() * inputs.size(0)\n",
    "        current_acc += torch.sum(predictions == labels.data)\n",
    "\n",
    "    total_loss = current_loss / len(data_loader.dataset)\n",
    "    total_acc = current_acc.double() / len(data_loader.dataset)\n",
    "\n",
    "    print('Test Loss: {:.4f}; Accuracy: {:.4f}'.format(total_loss, total_acc))\n",
    "\n",
    "    return total_loss, total_acc"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "8.`plot_accuracy`用于绘图"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [],
   "source": [
    "def plot_accuracy(accuracy: list):\n",
    "    \"\"\"Plot accuracy\"\"\"\n",
    "    plt.figure()\n",
    "    plt.plot(accuracy)\n",
    "    plt.xticks(\n",
    "        [i for i in range(0, len(accuracy))],\n",
    "        [i + 1 for i in range(0, len(accuracy))])\n",
    "    plt.ylabel('Accuracy')\n",
    "    plt.xlabel('Epoch')\n",
    "    plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "9.构建训练数据training dataset transformations (`transform_train`) 和 `train_loader`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Downloading https://www.cs.toronto.edu/~kriz/cifar-10-python.tar.gz to ../data\\cifar-10-python.tar.gz\n"
     ]
    },
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "56e55aae77084a6c91ba956f3f317a96",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "  0%|          | 0/170498071 [00:00<?, ?it/s]"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Extracting ../data\\cifar-10-python.tar.gz to ../data\n"
     ]
    }
   ],
   "source": [
    "# training data transformation\n",
    "transform_train = transforms.Compose([\n",
    "    transforms.RandomCrop(32, padding=4),\n",
    "    transforms.RandomHorizontalFlip(),\n",
    "    transforms.ToTensor(),\n",
    "    transforms.Normalize((0.4914, 0.4821, 0.4465), (0.2470, 0.2435, 0.2616))\n",
    "])\n",
    "\n",
    "# training data loader\n",
    "train_set = torchvision.datasets.CIFAR10(root='../data',\n",
    "                                         train=True,\n",
    "                                         download=True,\n",
    "                                         transform=transform_train)\n",
    "\n",
    "train_loader = torch.utils.data.DataLoader(dataset=train_set,\n",
    "                                           batch_size=100,\n",
    "                                           shuffle=True,\n",
    "                                           num_workers=2)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "10.构建验证数据"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Files already downloaded and verified\n"
     ]
    }
   ],
   "source": [
    "# test data transformation\n",
    "transform_test = transforms.Compose([\n",
    "    transforms.ToTensor(),\n",
    "    transforms.Normalize((0.4914, 0.4821, 0.4465), (0.2470, 0.2435, 0.2616))\n",
    "])\n",
    "\n",
    "# test data loader\n",
    "testset = torchvision.datasets.CIFAR10(root='../data',\n",
    "                                       train=False,\n",
    "                                       download=True,\n",
    "                                       transform=transform_test)\n",
    "\n",
    "test_loader = torch.utils.data.DataLoader(dataset=testset,\n",
    "                                          batch_size=100,\n",
    "                                          shuffle=False,\n",
    "                                          num_workers=2)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "11.定义`device`, `model`, `loss_function` 和`optimizer`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [],
   "source": [
    "model=PreActivationResNet34()\n",
    "\n",
    "device=torch.device(\"cuda:0\" if torch.cuda.is_available() else \"cpu\")\n",
    "\n",
    "model=model.to(device)\n",
    "\n",
    "loss_function=nn.CrossEntropyLoss()\n",
    "\n",
    "optimizer=optim.Adam(model.parameters())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "12.开始训练"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 1/5\n",
      "Train Loss:2.1317; Accuracy:0.2553\n",
      "Test Loss: 1.7460; Accuracy: 0.3569\n",
      "Epoch 2/5\n",
      "Train Loss:1.5679; Accuracy:0.4206\n",
      "Test Loss: 1.3427; Accuracy: 0.5066\n",
      "Epoch 3/5\n",
      "Train Loss:1.2924; Accuracy:0.5293\n",
      "Test Loss: 1.2793; Accuracy: 0.5592\n",
      "Epoch 4/5\n",
      "Train Loss:1.0954; Accuracy:0.6060\n",
      "Test Loss: 1.2527; Accuracy: 0.5774\n",
      "Epoch 5/5\n",
      "Train Loss:0.9516; Accuracy:0.6641\n",
      "Test Loss: 1.0041; Accuracy: 0.6662\n"
     ]
    }
   ],
   "source": [
    "EPCOHS=5\n",
    "\n",
    "test_acc=list()\n",
    "for epoch in range(EPCOHS):\n",
    "    print('Epoch {}/{}'.format(epoch+1,EPCOHS))\n",
    "\n",
    "    train_model(model,loss_function,optimizer,train_loader)\n",
    "    _,acc=test_model(model,loss_function,test_loader)\n",
    "    test_acc.append(acc)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "13.绘制准确率"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[tensor(0.3569, device='cuda:0', dtype=torch.float64), tensor(0.5066, device='cuda:0', dtype=torch.float64), tensor(0.5592, device='cuda:0', dtype=torch.float64), tensor(0.5774, device='cuda:0', dtype=torch.float64), tensor(0.6662, device='cuda:0', dtype=torch.float64)]\n",
      "[array(0.3569), array(0.5066), array(0.5592), array(0.5774), array(0.6662)]\n"
     ]
    },
    {
     "data": {
      "image/png": "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GRmQSCTIy8vDiBEjHlhDnz59NP9saWkJa2trFBUVtfSSiEhEDEBEpBcsLS0bPZL6MxKJBAAgCILmn5vax9zcvFnnMzExaXSsWq3WqiYi0g0cA0REHcLp06cbvff39wcA9OzZEykpKaisrNR8fuLECUilUvj6+sLa2hpdu3bFL7/80q41E5F4eAeIiPSCUqlEQUFBg23Gxsawt7cHAOzcuRNBQUEYPHgwtm3bhjNnzuCrr74CADz33HN49913MW3aNLz33nu4efMm5s2bh6lTp8LJyQkA8N5772H27NlwdHTEmDFjUF5ejhMnTmDevHnte6FE1C4YgIhIL/z0009wcXFpsM3Pzw8XL14EUD9Da8eOHXjttdfg7OyMbdu2oWfPngAACwsL/Pzzz5g/fz4GDhwICwsLPPXUU1i5cqXmXNOmTUN1dTVWrVqFRYsWwd7eHpMmTWq/CySidiURBEEQuwgioochkUiwe/duTJgwQexSiEhPcAwQERERGRwGICIiIjI4HANERHqPT/KJSFu8A0REREQGhwGIiIiIDA4DEBERERkcBiAiIiIyOAxAREREZHAYgIiIiMjgMAARERGRwWEAIiIiIoPz//VxQGNhW1/eAAAAAElFTkSuQmCC",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "print(test_acc)\n",
    "test_acc_numpy=[]\n",
    "for tem in test_acc:\n",
    "    aa=tem.cpu().numpy()\n",
    "    test_acc_numpy.append(aa)\n",
    "print(test_acc_numpy)\n",
    "\n",
    "plot_accuracy(test_acc_numpy)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "base",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.13"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
